using System;
using Tycho.Parser.Peg;

namespace Tycho.Grammar {
    public class DynamicParser : IParser {
        private readonly IDynamicGrammar DynamicGrammar;
        private readonly IProduction Production;

        public DynamicParser (IDynamicGrammar dynamicGrammar, IProduction production) {
            DynamicGrammar = dynamicGrammar;
            Production = production;
        }

        public ITerm ParseTerm (string source, string filename) {
            IProductionParser parser = new ProductionParser (Production, DynamicGrammar);
            return parser.Parse (source, filename);
        }

        public static DynamicParser CompileGrammar (string source) {
            ITerm grammarTerm = ParseGrammar (source);

            var grammarCompiler = new GrammarCompiler ();

            var environment = new IdentifierProductionCompilerEvaluator (IntegerProduction.CreateTerminal ());
            IProductionLookup productionLookup = CreateProductionLookup ();

            IDynamicGrammar dynamicGrammar = new LazyDynamicGrammar ();
            IProduction production = grammarCompiler.Compile (grammarTerm, environment, productionLookup, dynamicGrammar).Production;

            return new DynamicParser (dynamicGrammar, production);
        }

        private static ITerm ParseGrammar (string source) {
            var grammarParser = GrammarLoader.CreateGrammar ();
            IProductionParser parser = new ProductionParser (grammarParser);
            return parser.Parse (source, "filename");
        }

        private static IProductionLookup CreateProductionLookup () {
            var productionLookup = new ProductionLookup ();

            productionLookup.Add ("id", IdentifierProduction.CreateTerminal ());
            productionLookup.Add ("module-id", TychoIdentifierFactory.CreateTychoIdentifierProduction ());
            productionLookup.Add ("int", IntegerProduction.CreateTerminal ());
            productionLookup.Add ("float", FloatingPointProduction.CreateTerminal ());

            return productionLookup;
        }
    }
}